package com.dimld.utils;


import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Tools {

    private static final char[] HEX_CODE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
                                            'f'};

    private static final String[] HexCode = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e",
                                             "f"};

    private Tools() {
    }

    public static String bytesToStrings(byte[] b) {
        StringBuilder s = new StringBuilder();
        for (byte aB : b) {
            s.append(aB).append(",");
        }
        return s.toString();
    }

    public static byte[] stringToBytes(String s) {
        if (s.equals(""))
            return new byte[0];
        String[] bytes = s.split(",");
        byte[]   b     = new byte[s.length()];
        for (int i = 0, length = bytes.length; i < length; i++) {
            b[i] = (byte) Integer.parseInt(bytes[i]);
        }
        return b;
    }

    public static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n = 256 + n;
        int d1 = n / 16;
        int d2 = n % 16;
        return HexCode[d1] + HexCode[d2];
    }

    public static String byteArrayToHexString(byte b[]) {
        return byteArrayToHexString(b, 0, b.length);
    }

    private static String byteArrayToHexString(byte b[], int offset, int length) {
        StringBuilder result = new StringBuilder(length * 2);
        for (int i = 0; i < length; i++) {
            int n = b[offset + i];
            if (n < 0)
                n = 256 + n;
            result.insert(2 * i, HEX_CODE[(n >> 4)]);
            result.insert(2 * i + 1, HEX_CODE[n & 0x0f]);
        }
        return result.toString();
    }

    public static int byte2int(byte b[], int offset) {
        return b[offset + 3] & 0xff | (b[offset + 2] & 0xff) << 8 | (b[offset + 1] & 0xff) << 16
               | (b[offset] & 0xff) << 24;
    }

    public static int byte2int(byte b[]) {
        return b[3] & 0xff | (b[2] & 0xff) << 8 | (b[1] & 0xff) << 16 | (b[0] & 0xff) << 24;
    }

    public static short byte2short(byte b[]) {
        return (short) (b[1] & 0xff | (b[0] & 0xff) << 8);
    }

    public static int byte2unsignedShort(byte b[], int offset) {
        return b[offset + 1] & 0xff | (b[offset] & 0xff) << 8;
    }

    public static int unsignedByte2int(byte b) {
        return b & 0xff;
    }

    public static long byte2long(byte b[]) {
        return (long) b[7] & (long) 255 | ((long) b[6] & (long) 255) << 8 | ((long) b[5] & (long) 255) << 16
               | ((long) b[4] & (long) 255) << 24 | ((long) b[3] & (long) 255) << 32 | ((long) b[2] & (long) 255) << 40
               | ((long) b[1] & (long) 255) << 48 | (long) b[0] << 56;
    }

    public static long byte2long(byte b[], int offset) {
        return (long) b[offset + 7] & (long) 255 | ((long) b[offset + 6] & (long) 255) << 8
               | ((long) b[offset + 5] & (long) 255) << 16 | ((long) b[offset + 4] & (long) 255) << 24
               | ((long) b[offset + 3] & (long) 255) << 32 | ((long) b[offset + 2] & (long) 255) << 40
               | ((long) b[offset + 1] & (long) 255) << 48 | (long) b[offset] << 56;
    }

    public static byte[] int2byte(int n) {
        byte b[] = new byte[4];
        b[0] = (byte) (n >> 24);
        b[1] = (byte) (n >> 16);
        b[2] = (byte) (n >> 8);
        b[3] = (byte) n;
        return b;
    }

    /**
     * n 为待转数据，buf[]为转换后的数据，offset为buf[]中转换的起始点 转换后数据从低到高位
     */
    public static void int2byte(int n, byte buf[], int offset) {
        buf[offset] = (byte) (n >> 24);
        buf[offset + 1] = (byte) (n >> 16);
        buf[offset + 2] = (byte) (n >> 8);
        buf[offset + 3] = (byte) n;
    }

    public static byte[] short2byte(int n) {
        byte b[] = new byte[2];
        b[0] = (byte) (n >> 8);
        b[1] = (byte) n;
        return b;
    }

    public static void short2byte(int n, byte buf[], int offset) {
        buf[offset] = (byte) (n >> 8);
        buf[offset + 1] = (byte) n;
    }

    public static byte[] long2byte(long n) {
        byte b[] = new byte[8];
        b[0] = (byte) (int) (n >> 56);
        b[1] = (byte) (int) (n >> 48);
        b[2] = (byte) (int) (n >> 40);
        b[3] = (byte) (int) (n >> 32);
        b[4] = (byte) (int) (n >> 24);
        b[5] = (byte) (int) (n >> 16);
        b[6] = (byte) (int) (n >> 8);
        b[7] = (byte) (int) n;
        return b;
    }

    public static void long2byte(long n, byte buf[], int offset) {
        buf[offset] = (byte) (int) (n >> 56);
        buf[offset + 1] = (byte) (int) (n >> 48);
        buf[offset + 2] = (byte) (int) (n >> 40);
        buf[offset + 3] = (byte) (int) (n >> 32);
        buf[offset + 4] = (byte) (int) (n >> 24);
        buf[offset + 5] = (byte) (int) (n >> 16);
        buf[offset + 6] = (byte) (int) (n >> 8);
        buf[offset + 7] = (byte) (int) n;
    }

    /**
     * 将四个字节转化为整数
     *
     * @param mybytes
     * @return
     */
    public static int bytes4ToInt(byte mybytes[]) {
        return (0xff & mybytes[0]) << 24 | (0xff & mybytes[1]) << 16 | (0xff & mybytes[2]) << 8 | 0xff & mybytes[3];
    }

    /**
     * 将整数转化为四个字节的数组
     *
     * @param i
     * @return
     */
    public static byte[] intToBytes4(int i) {
        byte mybytes[] = new byte[4];
        mybytes[3] = (byte) (0xff & i);
        mybytes[2] = (byte) ((0xff00 & i) >> 8);
        mybytes[1] = (byte) ((0xff0000 & i) >> 16);
        mybytes[0] = (byte) ((0xff000000 & i) >> 24);
        return mybytes;
    }

    public static void bytesCopy(byte source[], byte dest[], int sourcebegin, int sourceend, int destbegin) {
        int j = 0;
        for (int i = sourcebegin; i <= sourceend; i++) {
            dest[destbegin + j] = source[i];
            j++;
        }

    }

    /**
     * Convert byte[] to hex
     * string.这里我们可以将byte转换成int，然后利用Integer.toHexString(int)来转换成16进制字符串。
     *
     * @param src byte[] data
     * @return hex string
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte aSrc : src) {
            int    v  = aSrc & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * Convert hex string to byte[]
     *
     * @param hexString the hex string
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int    length   = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d        = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    /**
     * Convert char to byte
     *
     * @param c char
     * @return byte
     */
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static void copy(String src, byte[] data, int destPos) {
        if (src != null) {
            byte[] temp;
            temp = src.getBytes(StandardCharsets.UTF_8);
            System.arraycopy(temp, 0, data, destPos, temp.length);
        }
    }

    /**
     * 返回号码状态、归属地条件、源号码
     *
     * @param tel
     * @return 返回为String数组，下标0值为1为手机，为2是固话，3是错误号。下标1为查询归属地所用(手机返回前7位,固话返回前3-4位)。下标2为正常号码，手机带0后去掉0
     */
    public static String[] checkTelType(String tel) {
        if (tel == null) {
            return null;
        }
        if (!isNumeric(tel)) {
            return null;
        }
        tel = tel.trim();
        if (!tel.equals("") && tel.length() > 7) {
            String s  = (tel.indexOf("0") == 0) ? tel.substring(1) : tel;// 如果首位为0，去掉0
            int    s2 = Integer.parseInt(s.substring(0, 2));// 截取前两位
            if (s2 > 10 && s2 < 20) {// 如果在10和20区间，判断为手机号
                tel = s.substring(0, 7);// 生成前7位
                return new String[]{"1", tel, s};
            } else {// 判断为固话，如果号段在30以下，判断为3位号段，010-029，否则为4位号段
                String tel_pre = (s2 < 30) ? tel.substring(0, 3) : tel.substring(0, 4);
                return new String[]{"2", tel_pre, tel};
            }
        } else {
            return new String[]{"3", "未知", tel};
        }
    }

    public static String join(Object[] o, String flag) {
        StringBuilder str_buff = new StringBuilder();

        for (int i = 0, len = o.length; i < len; i++) {
            str_buff.append(String.valueOf(o[i]));
            if (i < len - 1)
                str_buff.append(flag);
        }

        return str_buff.toString();
    }

    /**
     * HashMap转换为sql需要的语句，如where或update需要用到
     *
     * @param hm   需要转换的HashMap
     * @param join 连接字符，一般为等号[=]
     * @param pre  值前缀，一般为单引号[']
     * @param suf  值后缀，一般为单引号[']
     * @param flag 分割符，一般为逗号[,]
     * @return 生成后的字符串
     */
    public static String HashMapIterator_toSql(HashMap<String, Object> hm, String join, String pre, String suf,
                                               String flag) {
        StringBuilder ret = new StringBuilder();
        for (Map.Entry<String, Object> entry : hm.entrySet()) {
            String key = entry.getKey();
            Object val = entry.getValue();
            if (val instanceof Integer) {// 如果是int
                if ((Integer) val != 0) {
                    ret.append("`").append(key).append("`").append(join).append(pre).append(val).append(suf).append(flag);
                }
            } else {// 判断为字符串
                if (!String.valueOf(val).equals("")) {
                    ret.append("`").append(key).append("`").append(join).append(pre).append(val).append(suf).append(flag);
                }
            }
        }
        if (!ret.toString().equals("")) {
            ret.deleteCharAt(ret.length() - 1);
        }
        return ret.toString();
    }

    public static String textToHtml(String content) {
        if (content == null)
            return "";
        String html = content;
        html = html.replace("'", "&apos;");
        html = html.replaceAll("&", "&amp;");
        html = html.replace("\"", "&quot;"); // "
        html = html.replace("\t", "&nbsp;&nbsp;");// 替换跳格
        html = html.replace(" ", "&nbsp;");// 替换空格
        html = html.replace("<", "&lt;");

        html = html.replaceAll(">", "&gt;");
        return html;
    }

    /**
     * 将异常信息转换为字符串
     *
     * @param t
     * @return
     */
    public static String getTrace(Throwable t) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter  writer       = new PrintWriter(stringWriter);
        t.printStackTrace(writer);
        StringBuffer buffer = stringWriter.getBuffer();
        return buffer.toString();
    }

    /**
     * 按特定字符进行implode
     *
     * @param set
     * @param separator
     * @return
     */
    public static String setToString(Set<Object> set, String separator) {
        Iterator<Object> it = set.iterator();
        StringBuilder    s  = new StringBuilder();
        while (it.hasNext()) {
            s.append(String.valueOf(it.next())).append(separator);
        }
        if (s.length() > 1) {
            return s.substring(0, s.length() - separator.length());
        } else {
            return s.toString();
        }
    }

    public static Map<String, Object> bean2Map(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        try {
            BeanInfo             beanInfo            = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (!key.equals("class")) {// 过滤class属性
                    Method getter = property.getReadMethod();// 得到property对应的getter方法
                    Object value  = getter.invoke(obj);
                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            System.out.println("transBean2Map Error " + e);
        }

        return map;

    }

    public static String getAppPath() {
        Class<Tools> cls    = Tools.class;
        ClassLoader  loader = cls.getClassLoader();
        String        clsName = cls.getName() + ".class";
        Package       pack    = cls.getPackage();
        StringBuilder path    = new StringBuilder();
        if (pack != null) {
            String packName = pack.getName();
            // System.out.println("packName:" + packName);
            clsName = clsName.substring(packName.length() + 1);
            // System.out.println("clsName:" + clsName);
            if (!packName.contains("."))
                path = new StringBuilder(packName + "/");
            else {
                int start = 0, end;
                end = packName.indexOf(".");
                while (end != -1) {
                    path.append(packName, start, end).append("/");
                    start = end + 1;
                    end = packName.indexOf(".", start);
                }
                path.append(packName.substring(start)).append("/");
            }
        }
        // System.out.println("path:" + path);
        java.net.URL url      = loader.getResource(path + clsName);
        String       realPath = Objects.requireNonNull(url).getPath();
        // System.out.println("realPath:" + realPath);
        int pos = realPath.indexOf("file:");
        if (pos > -1) {
            realPath = realPath.substring(pos + 5);
        }
        pos = realPath.indexOf(path + clsName);
        realPath = realPath.substring(0, pos - 1);
        // System.out.println("realPath:" + realPath);
        // if (realPath.lastIndexOf(".") == realPath.length() - 1) {
        // realPath = realPath.substring(0, realPath.lastIndexOf("/"));
        // }
        realPath = realPath.substring(0, realPath.lastIndexOf("/"));
        // System.out.println("realPath.lastIndexOf():" +
        // realPath.lastIndexOf("/"));
        // System.out.println("realPath:" + realPath);
        return realPath;
    }// getAppPath定义 结束

    public static String getJsonNode(String nodeName, String content) {
        content = content.replaceAll(": \"", ":\"");
        String  reg = "(\"" + nodeName + "\":.*?[,|}])";
        Pattern p   = Pattern.compile(reg);
        Matcher m   = p.matcher(content);
        if (m.find()) {
            String find = m.group(1);
            if (find.lastIndexOf("\"") == find.length() - 2) {
                find = find.substring(4 + nodeName.length(), find.length() - 2);
            } else {
                find = find.substring(3 + nodeName.length(), find.length() - 1);
            }
            return find;
        }
        return null;
    }

    public static void execShell(String shellPath) {
        try {
            Process           process = Runtime.getRuntime().exec(shellPath);
            InputStreamReader ir      = new InputStreamReader(process.getInputStream());
            LineNumberReader  input   = new LineNumberReader(ir);
            String            line;
            while ((line = input.readLine()) != null)
                System.out.println(line);
            input.close();
            ir.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String execCmd(String cmd) {
        StringBuilder result = new StringBuilder();
        try {
            Process           process = Runtime.getRuntime().exec(cmd);
            InputStreamReader ir      = new InputStreamReader(process.getInputStream());
            LineNumberReader  input   = new LineNumberReader(ir);
            String            line;
            while ((line = input.readLine()) != null) {
                result.append(line).append("\r\n");
            }
            input.close();
            ir.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }

    public static String getLocalIP() {
        InetAddress addr = null;
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        if (addr != null) {
            return addr.getHostAddress();// 获得本机IP
        } else {
            return "";
        }
    }

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static String formatYearMonth(Integer year, Integer month) {
        month++;
        if (month < 10) {
            return year + "0" + month;
        } else {
            return year + "" + month;
        }
    }

    public static String filterHTML(String str) {
        if (str != null) {
            str = str.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("'", "&lsquo;")
                     .replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        }
        return str;
    }

    private static String FullIP2shortIP(String fullIP) {
        if (fullIP == null) {
            return "";
        } else if (fullIP.contains(":")) {
            return fullIP.split(":")[0].replaceAll("[^\\d|\\.]", "");
        } else {
            return fullIP;
        }
    }

    /**
     * 利用正则表达式判断字符串是否是数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum   = pattern.matcher(str);
        return isNum.matches();
    }

    public static void main(String[] args) {
        // System.out.println(Tools.base64DecodeToString("MTIzLjU2LjEyOS4yODo5MDI1"));
        // System.out.println(Tools.base64Encode("123.56.129.28:9025"));
        System.out.println(Tools.FullIP2shortIP("192.168.177.183:8898/"));
    }
}